package com.oocl.euc.authentication.tool;

import com.oocl.euc.authentication.core.SSOUserContext;
import com.oocl.euc.framework.authentication.common.JwtToken;
import com.oocl.euc.framework.authentication.exception.InvalidJwtTokenException;
import com.oocl.euc.framework.authentication.exception.JwtTokenExpiredException;
import com.oocl.euc.framework.authentication.jwt.JwtSettings;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.stream.Collectors;

@Component
public class SsoTokenHelper {

    @Autowired
    JwtSettings jwtSettings;

    public JwtToken createAccessTokenWithOpenToken(SSOUserContext userContext, String openToken) {
        if(null == userContext.getUserInfo() || StringUtils.isBlank(userContext.getUserInfo().getDomainId())){
            throw new IllegalArgumentException("Can not create token without username");
        }

        Claims claims = Jwts.claims().setSubject(userContext.getUserInfo().getDomainId());
        if(null != userContext.getRoles()) {
            claims.put("roles", userContext.getRoles().stream().map(s -> s.getAuthority()).collect(Collectors.toList()));
        }
        claims.put("userInfo", userContext.getUserInfo());
        claims.put("openToken", openToken);

        LocalDateTime currentTime = LocalDateTime.now();

        String token = Jwts.builder()
                .setClaims(claims)
                .setIssuer(getJwtSettings().getTokenIssuer())
                .setIssuedAt(Date.from(currentTime.atZone(ZoneId.systemDefault()).toInstant()))
                .setExpiration(Date.from(currentTime.plusMinutes(getJwtSettings().getTokenExpirationTime())
                        .atZone(ZoneId.systemDefault()).toInstant()))
                .signWith(SignatureAlgorithm.HS512, getJwtSettings().getTokenSigningKey())
                .compact();
        return new JwtToken(token, claims);
    }

    public Jws<Claims> parseClaims(String signingKey, String accessToken) {
        try {
            return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(accessToken);
        } catch (ExpiredJwtException e) {
            throw new JwtTokenExpiredException("Authentication Failed: JWT token expired");
        } catch (UnsupportedJwtException | IllegalArgumentException | MalformedJwtException | SignatureException e) {
            throw new InvalidJwtTokenException("Authentication Failed: Invalid JWT token");
        }
    }

    protected JwtSettings getJwtSettings() {
        return jwtSettings;
    }
}
